ffi: throw ERR_INVALID_ARG_TYPE for wrong-typed pointer and size - #65842
Open
soulee-dev wants to merge 2 commits into
Open
ffi: throw ERR_INVALID_ARG_TYPE for wrong-typed pointer and size#65842soulee-dev wants to merge 2 commits into
soulee-dev wants to merge 2 commits into
Conversation
ffi.getInt8() through ffi.getFloat64(), ffi.setInt8() through ffi.setFloat64(), ffi.toBuffer() and ffi.toArrayBuffer() return undefined instead of throwing when a required argument is omitted, so a call that read or wrote nothing cannot be told apart from one that read a zero byte. All 22 helpers behave this way. GetValidatedPointerAddress() and GetValidatedSize() already reject the same argument when it is passed explicitly as undefined. The args.Length() test in front of them short-circuits the call and returns Nothing without scheduling an exception. These six are the only tests in src/ where args.Length() can skip a call that throws; the only other Length() tests that guard a call at all guard Buffer::HasInstance(), which cannot throw. The remaining tests in this file guard an inline predicate and throw in the branch, which is why setUint8(ptr) reports "Expected an offset argument" while setUint8() reports nothing at all. Drop those tests. FunctionCallbackInfo::operator[] returns Undefined for an out-of-range index, which is exactly the value these validators reject, so each missing argument now produces the error its explicit undefined counterpart produces. The documentation already describes this behavior: the signatures are ffi.getInt8(pointer[, offset]), ffi.setInt8(pointer, offset, value) and ffi.toBuffer(pointer, length[, copy]), and the getters are documented to return a number or a bigint. ExportBytes() carried the same two tests. They are unreachable through the public API because exportBytes is not exported and its three callers all validate len in JavaScript first, but they are the same shape. Signed-off-by: Soul Lee <alus20x@gmail.com>
GetValidatedPointerAddress() and GetValidatedSize() throw ERR_INVALID_ARG_VALUE when the argument is not a bigint or not a number. doc/api/errors.md reserves that code for a value of the right type that is invalid or unsupported; a wrong type is ERR_INVALID_ARG_TYPE. That is what the JavaScript validators behind exportString() and exportBuffer() throw, and what the inline IsBigInt() checks in toString(), toBuffer() and toArrayBuffer() throw for their first argument. So ffi.exportBuffer(buf, ptr, 'x') reports a type error while ffi.toBuffer(ptr, 'x') reports a value error for the same mistake. Switch the two type-check branches to ERR_INVALID_ARG_TYPE. The branches that reject a negative or non-integer value, or a value outside the platform range, keep ERR_INVALID_ARG_VALUE and ERR_OUT_OF_RANGE. This changes the code thrown for a non-bigint pointer by the getters, the setters, exportBuffer(), exportArrayBuffer() and exportArrayBufferView(), and for a non-number offset or length by the getters, the setters, toBuffer() and toArrayBuffer(). The messages are unchanged. No existing test asserted ERR_INVALID_ARG_VALUE on any of these paths. Refs: nodejs#65500 Signed-off-by: Soul Lee <alus20x@gmail.com>
Collaborator
|
Review requested:
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #65842 +/- ##
==========================================
- Coverage 90.20% 90.19% -0.02%
==========================================
Files 771 771
Lines 264622 264619 -3
Branches 50228 50228
==========================================
- Hits 238704 238666 -38
- Misses 16907 16953 +46
+ Partials 9011 9000 -11
🚀 New features to boost your workflow:
|
jasnell
approved these changes
Sep 6, 2026
Collaborator
nodejs-github-bot
pushed a commit
that referenced
this pull request
Sep 6, 2026
ffi.getInt8() through ffi.getFloat64(), ffi.setInt8() through ffi.setFloat64(), ffi.toBuffer() and ffi.toArrayBuffer() return undefined instead of throwing when a required argument is omitted, so a call that read or wrote nothing cannot be told apart from one that read a zero byte. All 22 helpers behave this way. GetValidatedPointerAddress() and GetValidatedSize() already reject the same argument when it is passed explicitly as undefined. The args.Length() test in front of them short-circuits the call and returns Nothing without scheduling an exception. These six are the only tests in src/ where args.Length() can skip a call that throws; the only other Length() tests that guard a call at all guard Buffer::HasInstance(), which cannot throw. The remaining tests in this file guard an inline predicate and throw in the branch, which is why setUint8(ptr) reports "Expected an offset argument" while setUint8() reports nothing at all. Drop those tests. FunctionCallbackInfo::operator[] returns Undefined for an out-of-range index, which is exactly the value these validators reject, so each missing argument now produces the error its explicit undefined counterpart produces. The documentation already describes this behavior: the signatures are ffi.getInt8(pointer[, offset]), ffi.setInt8(pointer, offset, value) and ffi.toBuffer(pointer, length[, copy]), and the getters are documented to return a number or a bigint. ExportBytes() carried the same two tests. They are unreachable through the public API because exportBytes is not exported and its three callers all validate len in JavaScript first, but they are the same shape. Signed-off-by: Soul Lee <alus20x@gmail.com> PR-URL: #65500 Fixes: #65499 Refs: #62072 Refs: #62858 Refs: #65842 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day> Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GetValidatedPointerAddress()andGetValidatedSize()throwERR_INVALID_ARG_VALUEwhen the argument is not a bigint or not a number.ERR_INVALID_ARG_VALUEis reserved for a value of the right type that is invalid or unsupported; a wrong type isERR_INVALID_ARG_TYPE. That is what the JavaScript validators behindexportString()andexportBuffer()throw, and what the inlineIsBigInt()checks intoString(),toBuffer()andtoArrayBuffer()throw for their first argument, so the same mistake currently gets a different code depending on which helper reports it:Switch the two type-check branches to
ERR_INVALID_ARG_TYPE. The branches that reject a negative or non-integer value, or a value outside the platform range, keepERR_INVALID_ARG_VALUEandERR_OUT_OF_RANGE. The messages are unchanged.Affected paths
getInt8('x'),getInt8(undefined),getInt8()ERR_INVALID_ARG_VALUEERR_INVALID_ARG_TYPEsetInt8('x', 0, 1),setInt8(undefined, 0, 1),setInt8()ERR_INVALID_ARG_VALUEERR_INVALID_ARG_TYPEgetInt8(ptr, 'x'),setInt8(ptr, 'x', 1)ERR_INVALID_ARG_VALUEERR_INVALID_ARG_TYPEtoBuffer(ptr, 'x'),toArrayBuffer(ptr, 'x'),toBuffer(ptr)ERR_INVALID_ARG_VALUEERR_INVALID_ARG_TYPEexportBuffer(buf, 'x', 1),exportArrayBuffer(ab, 'x', 1),exportArrayBufferView(view, 'x', 1)ERR_INVALID_ARG_VALUEERR_INVALID_ARG_TYPEThe pointer argument of
toString(),toBuffer(),toArrayBuffer()andexportString()is unaffected: those already reject a non-bigint withERR_INVALID_ARG_TYPEbefore calling the helper. So is thelenargument of theexport*helpers, whichvalidateInteger()checks in JavaScript first. No existing test assertedERR_INVALID_ARG_VALUEon any of the affected paths.The first commit is #65500 and is not part of this PR; this one depends on it because it updates the assertions that PR adds.
Refs: #65500
Refs: #65500 (comment)